-
Notifications
You must be signed in to change notification settings - Fork 1.2k
refactor: move CSigSharesManager to ActiveContext, drop CActiveMasternodeManager from CSigSharesManager
#6841
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
|
This pull request has conflicts, please rebase. |
WalkthroughThe patch refactors LLMQ signing and sigshare ownership: CSigningManager drops the active masternode dependency and the AsyncSignIfMember API; CSigSharesManager gains a richer, stateful interface (AsyncSignIfMember, NotifyRecoveredSig, ctor/destructor) and is moved from llmq::LLMQContext into ActiveContext as an owned member (shareman). Multiple constructors and Start/Stop/Interrupt signatures were updated (LLMQContext, CChainLocksHandler, CSigningManager, CSigSharesManager, ActiveContext). Call sites across chainlock, instantsend, ehf, net_processing, rpc/quorums, and masternode activation were changed to use active_ctx->shareman and the new APIs. A corresponding expected circular dependency test entry was added. Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (6)
src/chainlock/chainlock.h (1)
8-19: Missing required headers in a public headerThis header declares std::unique_ptr, std::thread, std::chrono::seconds, and uses assert(), but doesn’t include , , , . Add IWYU-complete includes to prevent fragile transitive dependencies.
Apply:
#include <gsl/pointers.h> +#include <chrono> +#include <memory> +#include <thread> #include <atomic> #include <map> #include <unordered_map> +#include <cassert>src/chainlock/chainlock.cpp (2)
65-82: Dangling reference: scheduler lambda capturesismanby reference
Start(const CInstantSendManager& isman)schedules a lambda that outlives the function but captures[&]and usesisman. This is undefined behavior onceStart()returns.Capture a reference_wrapper by value (or store a member pointer) and capture
[this, isman_ref]:void CChainLocksHandler::Start(const llmq::CInstantSendManager& isman) { if (auto signer = m_signer.load(std::memory_order_acquire); signer) { signer->Start(); } - scheduler->scheduleEvery( - [&]() { + auto isman_ref = std::cref(isman); + scheduler->scheduleEvery( + [this, isman_ref]() { auto signer = m_signer.load(std::memory_order_acquire); CheckActiveState(); EnforceBestChainLock(); Cleanup(); // regularly retry signing the current chaintip as it might have failed before due to missing islocks if (signer) { - signer->TrySignChainTip(isman); + signer->TrySignChainTip(isman_ref.get()); } }, std::chrono::seconds{5}); }
219-233: Fix dangling references in scheduled lambdas: three instances require correctionThe review comment correctly identifies a dangling reference issue in chainlock.cpp and the grep found two additional dangling reference problems in net_processing.cpp. All three capture function parameters or local variables by reference in scheduled lambdas that will outlive those references.
Locations requiring fixes:
- src/chainlock/chainlock.cpp:219-233 —
UpdatedBlockTip: Captures function parameterismanby reference via[&]- src/net_processing.cpp:1672 —
ReattemptInitialBroadcast: Captures local variabledeltaby reference via[&]- src/net_processing.cpp:2021 —
StartScheduledTasks: Captures local variabledeltaby reference via[&]Apply the proposed fix pattern to all three: replace
[&]with explicit captures of necessary references usingstd::cref()for reference types, or pass by value where appropriate.src/llmq/signing.h (1)
8-20: IWYU: add andHeader declares
std::unique_ptrandstd::threadbut doesn’t include their headers.#include <util/threadinterrupt.h> #include <gsl/pointers.h> #include <string_view> #include <unordered_map> +#include <memory> +#include <thread>src/masternode/active/context.cpp (1)
1-1: Fix clang-format differences.The pipeline indicates formatting issues in this file. Please run
clang-formatto fix the formatting differences.[scratchpad_end] -->
#!/bin/bash # Verify the exact formatting differences git diff -U0 HEAD -- src/masternode/active/context.cpp | clang-format-diff -p1src/llmq/signing.cpp (1)
714-715: Rename thread to avoid name collision with CSigSharesManager.Duplicate "sigshares" thread names exist in both
src/llmq/signing_shares.cpp:206andsrc/llmq/signing.cpp:714. This hinders debugging and performance profiling. Rename to a distinct identifier:- workThread = std::thread(&util::TraceThread, "sigshares", [this, &peerman] { WorkThreadMain(peerman); }); + workThread = std::thread(&util::TraceThread, "recsigs", [this, &peerman] { WorkThreadMain(peerman); });
🧹 Nitpick comments (9)
src/chainlock/chainlock.h (1)
66-67: Avoid chrono UDLs in headers
lastCleanupTime{0s}relies onstd::chrono_literalsbeing in scope for every TU including this header. Use explicit construction.- std::atomic<std::chrono::seconds> lastCleanupTime{0s}; + std::atomic<std::chrono::seconds> lastCleanupTime{std::chrono::seconds{0}};src/masternode/active/notificationinterface.cpp (1)
30-33: Add a defensive assert before dereferencing shareman.Guard against accidental null in unusual init paths.
void ActiveNotificationInterface::NotifyRecoveredSig(const std::shared_ptr<const llmq::CRecoveredSig>& sig) { - m_active_ctx.shareman->NotifyRecoveredSig(sig); + assert(m_active_ctx.shareman); + m_active_ctx.shareman->NotifyRecoveredSig(sig); }src/rpc/quorums.cpp (1)
443-445: Consider checking active_ctx directly instead of mn_activeman.Currently, the code checks
node.mn_activemanto determine masternode mode, then usesCHECK_NONFATAL(node.active_ctx)when accessing shareman. While this works in practice (since active_ctx is created when mn_activeman exists), it would be more direct and safer to check active_ctx itself:- if (!node.mn_activeman) { - throw JSONRPCError(RPC_INTERNAL_ERROR, "Only available in masternode mode."); - } + if (!node.active_ctx) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Only available in masternode mode."); + }Then the shareman access can use the already-verified pointer:
- return CHECK_NONFATAL(node.active_ctx)->shareman->AsyncSignIfMember(...); + return node.active_ctx->shareman->AsyncSignIfMember(...);This avoids relying on indirect implications and provides clearer error handling.
Also applies to: 467-467, 481-481
src/llmq/signing.cpp (1)
10-11: Drop unneeded include to reduce coupling.
#include <llmq/signing_shares.h>is not used in this TU. Removing it shrinks compile dependencies and helps avoid cycles.-#include <llmq/signing_shares.h>src/llmq/context.cpp (1)
51-57: Start order: register listeners before starting sigman’s worker.To avoid a small race where early recovered-sig notifications are emitted before IS registers as a listener, start IS (and CL) first, then start sigman’s worker.
void LLMQContext::Start(PeerManager& peerman) { qman->Start(); - sigman->StartWorkerThread(peerman); clhandler->Start(*isman); isman->Start(peerman); + sigman->StartWorkerThread(peerman); }If current ordering is intentional, confirm that no notifications can fire before IS registers.
src/llmq/signing_shares.h (1)
407-414: Consider const-correctness for m_chainstate.
CSigSharesManagerreads from chainstate but doesn’t mutate it. Making itconst CChainState&tightens API guarantees.- CChainState& m_chainstate; + const CChainState& m_chainstate;src/llmq/signing_shares.cpp (3)
1206-1365: Message send batching LGTM; minor constant duplication note.
MAX_MSGS_*limits are duplicated across files; consider centralizing (optional).
1579-1601: Main loop order is sensible; small nit.You already run
RemoveBannedNodeStates()before work; consider placingCleanup()beforesleep_forto avoid extra 100ms latency after a busy cycle. Optional.
236-238: Use memberm_sporkmaninstead of parameter to eliminate redundant argument.CSigSharesManager stores
m_sporkmanas a member; refactor ProcessMessage to use it directly instead of accepting the same dependency as a parameter. The sporkman parameter is used only once in the function body (line 242).Update locations:
- src/llmq/signing_shares.h:432 — Remove
const CSporkManager& sporkmanparameter- src/llmq/signing_shares.cpp:236 — Remove parameter and replace
sporkman.IsSporkActive(...)withm_sporkman.IsSporkActive(...)- src/net_processing.cpp:5380 — Update call:
m_active_ctx->shareman->ProcessMessage(pfrom, msg_type, vRecv)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (19)
src/chainlock/chainlock.cpp(1 hunks)src/chainlock/chainlock.h(1 hunks)src/chainlock/signing.cpp(2 hunks)src/init.cpp(3 hunks)src/instantsend/signing.cpp(3 hunks)src/llmq/context.cpp(2 hunks)src/llmq/context.h(1 hunks)src/llmq/ehf_signals.cpp(2 hunks)src/llmq/signing.cpp(1 hunks)src/llmq/signing.h(2 hunks)src/llmq/signing_shares.cpp(37 hunks)src/llmq/signing_shares.h(4 hunks)src/masternode/active/context.cpp(3 hunks)src/masternode/active/context.h(2 hunks)src/masternode/active/notificationinterface.cpp(2 hunks)src/masternode/active/notificationinterface.h(2 hunks)src/net_processing.cpp(1 hunks)src/rpc/quorums.cpp(5 hunks)test/lint/lint-circular-dependencies.py(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
src/**/*.{cpp,h,cc,cxx,hpp}
📄 CodeRabbit inference engine (CLAUDE.md)
src/**/*.{cpp,h,cc,cxx,hpp}: Dash Core C++ codebase must be written in C++20 and require at least Clang 16 or GCC 11.1
Dash uses unordered_lru_cache for efficient caching with LRU eviction
Files:
src/net_processing.cppsrc/chainlock/chainlock.cppsrc/llmq/signing.hsrc/chainlock/chainlock.hsrc/masternode/active/context.hsrc/chainlock/signing.cppsrc/llmq/context.hsrc/llmq/ehf_signals.cppsrc/masternode/active/notificationinterface.hsrc/init.cppsrc/instantsend/signing.cppsrc/llmq/signing_shares.hsrc/llmq/signing.cppsrc/rpc/quorums.cppsrc/llmq/context.cppsrc/masternode/active/context.cppsrc/llmq/signing_shares.cppsrc/masternode/active/notificationinterface.cpp
src/{masternode,evo}/**/*.{cpp,h,cc,cxx,hpp}
📄 CodeRabbit inference engine (CLAUDE.md)
Masternode lists must use immutable data structures (Immer library) for thread safety
Files:
src/masternode/active/context.hsrc/masternode/active/notificationinterface.hsrc/masternode/active/context.cppsrc/masternode/active/notificationinterface.cpp
🧠 Learnings (2)
📚 Learning: 2025-01-02T21:50:00.967Z
Learnt from: kwvg
PR: dashpay/dash#6504
File: src/llmq/context.cpp:42-43
Timestamp: 2025-01-02T21:50:00.967Z
Learning: LLMQContext manages concurrency for the `CInstantSendManager`. Previously, this was handled globally; now it's handled as a class member in `LLMQContext`, but the concurrency control remains consistent.
Applied to files:
src/masternode/active/context.hsrc/llmq/context.h
📚 Learning: 2025-10-02T18:29:54.756Z
Learnt from: kwvg
PR: dashpay/dash#6840
File: src/net_processing.cpp:2882-2886
Timestamp: 2025-10-02T18:29:54.756Z
Learning: Across net_processing.cpp, once LLMQContext (m_llmq_ctx) is asserted non-null, its subcomponents (e.g., isman, qdkgsman, quorum_block_processor) are treated as initialized and used without extra null checks.
Applied to files:
src/masternode/active/context.hsrc/llmq/context.hsrc/llmq/context.cpp
🧬 Code graph analysis (12)
src/llmq/signing.h (2)
src/llmq/signing.cpp (3)
CSigningManager(335-340)CRecoveredSigsDb(30-33)CRecoveredSigsDb(35-35)src/llmq/signing_shares.cpp (2)
CSigSharesManager(183-195)CSigSharesManager(197-197)
src/chainlock/chainlock.h (1)
src/chainlock/chainlock.cpp (2)
CChainLocksHandler(46-57)CChainLocksHandler(59-63)
src/masternode/active/context.h (5)
src/llmq/context.cpp (6)
Interrupt(46-49)Interrupt(46-46)Start(51-57)Start(51-51)Stop(59-65)Stop(59-59)src/masternode/active/context.cpp (6)
Interrupt(49-52)Interrupt(49-49)Start(54-59)Start(54-54)Stop(61-66)Stop(61-61)src/init.cpp (2)
Interrupt(227-250)Interrupt(227-227)src/llmq/ehf_signals.h (2)
llmq(16-52)CEHFSignalsHandler(21-51)src/llmq/ehf_signals.cpp (2)
CEHFSignalsHandler(20-29)CEHFSignalsHandler(31-34)
src/llmq/context.h (3)
src/llmq/context.cpp (2)
Start(51-57)Start(51-51)src/masternode/active/context.cpp (2)
Start(54-59)Start(54-54)src/instantsend/instantsend.cpp (2)
Start(76-88)Start(76-76)
src/masternode/active/notificationinterface.h (3)
src/llmq/ehf_signals.h (1)
llmq(16-52)src/llmq/signing_shares.cpp (2)
NotifyRecoveredSig(952-955)NotifyRecoveredSig(952-952)src/masternode/active/notificationinterface.cpp (2)
NotifyRecoveredSig(30-33)NotifyRecoveredSig(30-30)
src/llmq/signing_shares.h (2)
src/llmq/signing_shares.cpp (24)
CSigSharesManager(183-195)CSigSharesManager(197-197)StartWorkerThread(199-207)StartWorkerThread(199-199)ProcessMessage(236-314)ProcessMessage(236-237)AsyncSignIfMember(872-950)AsyncSignIfMember(872-874)NotifyRecoveredSig(952-955)NotifyRecoveredSig(952-952)ProcessMessageSigSesAnn(316-346)ProcessMessageSigSesAnn(316-316)ProcessMessageSigSharesInv(354-389)ProcessMessageSigSharesInv(354-354)ProcessMessageGetSigShares(391-419)ProcessMessageGetSigShares(391-391)ProcessMessageBatchedSigShares(421-473)ProcessMessageBatchedSigShares(421-421)ProcessMessageSigShare(475-524)ProcessMessageSigShare(475-475)BanNode(1553-1577)BanNode(1553-1553)WorkThreadMain(1579-1601)WorkThreadMain(1579-1579)src/masternode/active/notificationinterface.cpp (2)
NotifyRecoveredSig(30-33)NotifyRecoveredSig(30-30)
src/llmq/signing.cpp (1)
src/llmq/signing.h (1)
CSigningManager(160-244)
src/rpc/quorums.cpp (1)
src/llmq/signing_shares.cpp (2)
SelectMemberForRecovery(857-870)SelectMemberForRecovery(857-857)
src/llmq/context.cpp (2)
src/instantsend/signing.cpp (4)
Start(49-52)Start(49-49)Stop(54-57)Stop(54-54)src/masternode/active/context.cpp (4)
Start(54-59)Start(54-54)Stop(61-66)Stop(61-61)
src/masternode/active/context.cpp (5)
src/node/interfaces.cpp (2)
Interrupt(426-430)Interrupt(431-436)src/llmq/context.cpp (6)
Interrupt(46-49)Interrupt(46-46)Start(51-57)Start(51-51)Stop(59-65)Stop(59-59)src/init.cpp (2)
Interrupt(227-250)Interrupt(227-227)src/chainlock/signing.cpp (4)
Start(33-36)Start(33-33)Stop(38-41)Stop(38-38)src/instantsend/signing.cpp (4)
Start(49-52)Start(49-49)Stop(54-57)Stop(54-54)
src/llmq/signing_shares.cpp (2)
src/llmq/signing.cpp (8)
StartWorkerThread(707-715)StartWorkerThread(707-707)WorkThreadMain(734-746)WorkThreadMain(734-734)ProcessMessage(393-433)ProcessMessage(393-393)Cleanup(635-648)Cleanup(635-635)src/net_processing.cpp (31)
ProcessMessage(3617-5411)ProcessMessage(3617-3622)pfrom(619-619)pfrom(640-641)pfrom(735-737)pfrom(746-746)pfrom(754-754)pfrom(757-757)pfrom(759-759)pfrom(761-761)pfrom(855-855)pfrom(1037-1037)inv(633-633)inv(634-634)inv(653-653)inv(659-659)inv(945-945)inv(2326-2326)id(685-685)id(689-689)SendMessages(5878-6478)SendMessages(5878-5878)LOCK(327-333)LOCK(340-344)LOCK(345-349)pnode(639-639)pnode(644-644)pnode(721-721)pnode(765-765)pnode(835-835)pnode(837-837)
src/masternode/active/notificationinterface.cpp (1)
src/llmq/signing_shares.cpp (2)
NotifyRecoveredSig(952-955)NotifyRecoveredSig(952-952)
🪛 GitHub Actions: Clang Diff Format Check
src/llmq/signing_shares.h
[error] 1-1: Clang-format differences found in src/llmq/signing_shares.h. Run 'clang-format' or the diff script to fix formatting.
src/masternode/active/context.cpp
[error] 1-1: Clang-format differences found in src/masternode/active/context.cpp. Run 'clang-format' or the diff script to fix formatting.
🔇 Additional comments (29)
src/chainlock/chainlock.cpp (1)
46-56: Constructor changes align with headerInit list removal of sigman is consistent and safe.
src/instantsend/signing.cpp (3)
16-17: Include addition is appropriateDirectly using CSigSharesManager API warrants including signing_shares.h.
392-393: Consistent usage of AsyncSignIfMemberCall site aligns with new signature; relying on default
fRetroactive=falseis fine.
328-336: Parameter order and function signature verification complete—no issues found.The function signature at
src/llmq/signing_shares.h:443-447confirms the parameter order is:AsyncSignIfMember(Consensus::LLMQType llmqType, CSigningManager& sigman, const uint256& id, const uint256& msgHash, const uint256& quorumHash = uint256(), bool allowReSign = false, bool allowDiffMsgHashSigning = false)Both calls in
src/instantsend/signing.cppalign correctly:
- Line 334:
AsyncSignIfMember(llmqType, m_sigman, id, tx.GetHash(), {}, fRetroactive)maps parameters correctly (quorumHash={}, allowReSign=fRetroactive)- Line 392:
AsyncSignIfMember(llmqType, m_sigman, id, tx.GetHash(), quorum->m_quorum_base_block_index->GetBlockHash())uses defaults appropriatelyAll other usages across the codebase follow the same consistent parameter order.
src/chainlock/signing.cpp (2)
12-13: Include addition is appropriateUsing CSigSharesManager API requires including its header.
144-145: AsyncSignIfMember call updated correctlyParam order matches new interface. No further issues.
src/llmq/signing.h (1)
181-182: Constructor signature change successfully propagated; all call sites updatedThe verification confirms the
CSigningManagerconstructor signature change is complete. The only instantiation site atsrc/llmq/context.cpp:33correctly uses the new 4-parameter signature withoutmn_activeman:std::make_unique<llmq::CSigningManager>(chainman.ActiveChainstate(), *qman, unit_tests, wipe)No stale 5-parameter call sites remain.
src/net_processing.cpp (1)
5378-5381: Move to ActiveContext::shareman looks good; please verify injection/lifetime.Dropping the explicit PeerManager param means CSigSharesManager must already hold the correct PeerManager reference. Confirm:
- ActiveContext builds shareman with this PeerManager instance.
- shareman’s lifetime ≥ PeerManagerImpl usage.
- No additional locks required beyond g_msgproc_mutex here.
src/masternode/active/notificationinterface.cpp (1)
9-9: Include is appropriate for calling CSigSharesManager APIs.OK to include signing_shares.h here since the method call needs the full type.
test/lint/lint-circular-dependencies.py (1)
72-72: Circular dependency confirmed; refactoring is recommended but optional.The cycle
llmq/signing_shares → net_processing → masternode/active/context → llmq/signing_sharesis real:
net_processing.cppincludesmasternode/active/context.hmasternode/active/context.cppincludesllmq/signing_shares.hllmq/signing_shares.cppincludesnet_processing.hAdding this to the expected circular dependencies list is acceptable if breaking the cycle is not feasible within this PR. However, the suggested refactoring approaches remain valid long-term improvements:
- Extract a minimal interface header (e.g.,
net/peerman_iface.h) to decouplellmq/signing_sharesfromnet_processing- Introduce an
ISigSharesManagerinterface inmasternode/active/contextto eliminate the dependency chainIf this cycle was newly introduced by the PR's refactoring, consider whether these decoupling strategies could be applied now; otherwise, this is a good candidate for a follow-up refactoring effort.
src/masternode/active/notificationinterface.h (1)
10-10: LGTM!The additions properly integrate recovered signature notifications into the active masternode notification interface. The forward declaration avoids unnecessary header dependencies, and the method signature follows the validation interface pattern correctly.
Also applies to: 14-16, 28-28
src/llmq/ehf_signals.cpp (1)
14-17: LGTM!The include additions and
AsyncSignIfMemberparameter adjustment align with the refactor to move CSigSharesManager to ActiveContext and adjust dependency flow between signing managers.Also applies to: 81-81
src/masternode/active/context.cpp (1)
29-37: LGTM!The shareman initialization and lifecycle method implementations are correct. The refactor properly moves CSigSharesManager ownership to ActiveContext and wires it into the startup/shutdown sequence alongside the existing LLMQ DKG session manager.
Also applies to: 49-66
src/llmq/context.h (1)
44-44: LGTM!The Start method signature change and removal of shareman member are consistent with the refactor goals. CSigSharesManager ownership has been successfully moved to ActiveContext, and LLMQContext.Start no longer requires CConnman since it doesn't manage shareman anymore.
Based on learnings.
src/init.cpp (1)
234-236: LGTM!The lifecycle integration for ActiveContext follows the correct dependency order:
- Startup: llmq_ctx → active_ctx (base first, dependents second)
- Shutdown: active_ctx → llmq_ctx (dependents first, base second)
The Start method parameter changes align with the refactored ownership model.
Also applies to: 272-272, 2259-2260
src/masternode/active/context.h (1)
33-33: LGTM!The interface design is sound:
- Forward declaration minimizes dependencies
- Public lifecycle methods follow established patterns
- shareman is appropriately public for external access
- cl_signer and is_signer are correctly private since they're managed through registration
The access levels reflect proper encapsulation.
Also applies to: 50-52, 61-61, 64-70
src/rpc/quorums.cpp (1)
31-31: LGTM!The include addition enables access to ActiveContext, and the SelectMemberForRecovery change to use the static method is appropriate since it's a pure function called from a non-masternode-specific RPC command.
Also applies to: 750-750
src/llmq/signing.cpp (1)
335-340: Ctor change LGTM; dependency slimming achieved.Dropping CActiveMasternodeManager here is clean and consistent with the PR goal. No functional risk spotted.
src/llmq/context.cpp (1)
33-36: Ctor wiring LGTM.Updated CSigningManager and CChainLocksHandler ctor args align with the refactor.
src/llmq/signing_shares.h (3)
419-423: New constructor/dtor LGTM.Explicit ctor with all dependencies, plus virtual dtor override, improves ownership clarity.
443-447: Verification confirms new API migration complete.All 5 caller sites (rpc/quorums.cpp, ehf_signals.cpp, instantsend/signing.cpp, chainlock/signing.cpp) correctly use the new API pattern where
AsyncSignIfMemberis invoked on shareman with sigman passed as a parameter. No legacy calls using the old API remain in the codebase.
1-7: Apply clang-format to fix formatting violations in this file.The file contains formatting issues that violate the project's
.clang-formatconfiguration, specifically:
- Excessive blank lines (3+) at lines 104–108 and similar locations exceed the
MaxEmptyLinesToKeep: 2limit- Include organization may need adjustment
Run clang-format locally on
src/llmq/signing_shares.husing:clang-format -i src/llmq/signing_shares.hThen commit the formatting changes to unblock CI.
src/llmq/signing_shares.cpp (7)
183-195: Ctor wiring LGTM.Capturing deps by reference and resetting the interrupt is correct.
199-207: Worker start LGTM.Parameterless
StartWorkerThread()aligns with member-internalized deps.
639-705: Banning invalid lazy sigs is strict; confirm policy.On invalid lazy sig deserialization, you ban immediately. If that’s intentional, all good; otherwise consider penalizing less harshly first.
Do we have prior art in net_processing for equivalent penalties?
725-774: Recovery flow LGTM.On threshold reached, attempt recovery; single-member special-case is handled; sporadic verification guards against regressions.
Also applies to: 776-855
1150-1204: Announcement path LGTM; uses quorum node discovery once per quorum.The memoization via quorumNodesMap avoids repeated GetMasternodeQuorumNodes calls.
1532-1577: Ban flow uses PeerManager::Misbehaving/IsBanned; good encapsulation.Local state is cleaned up to re-request from others; matches resiliency goals.
1635-1655: Single-quorum signing still uses operator key; TODO acknowledged.Noted; leaving as-is matches existing behavior.
We initialize the masternode mode context later and as it's explicitly networking-heavy, we can move CConnman and PeerManager back into the ctor and trim down the arguments list a fair bit. Effectively reverts 82d1aed.
Giving write access of CRecoveredSigsDb to an external manager isn't great but we have to do this if we want to drop CActiveMasternodeManager from CSigSharesManager Review with `git log -p -n1 --color-moved=dimmed_zebra`.
As ProcessRecoveredSig() triggers a NotifyRecoveredSig() notification, we can stick the RelayRecoveredSig() into CSigSharesManager and have the relay request processed through the notification interface instead, lets us finally drop CActiveMasternodeManager from CSigSharesManager.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/llmq/signing_shares.h (1)
20-30: Include NodeId definition.This header uses NodeId in public types/APIs but doesn’t include net_types.h; include-what-you-use to avoid order-dependent builds.
#include <uint256.h> #include <atomic> #include <limits> #include <memory> #include <optional> #include <string> #include <thread> #include <unordered_map> #include <utility> #include <vector> +// Needed for NodeId +#include <net_types.h>src/rpc/quorums.cpp (1)
467-481: Verify active_ctx availability more explicitly.Both calls use
CHECK_NONFATAL(node.active_ctx)which will abort in debug builds but could lead to undefined behavior in release builds if active_ctx is null. Since masternode mode is already verified at line 443-445, and active_ctx should exist when mn_activeman exists, consider adding an explicit check:if (!node.mn_activeman) { throw JSONRPCError(RPC_INTERNAL_ERROR, "Only available in masternode mode."); } +if (!node.active_ctx) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Active masternode context not available."); +}This provides better error handling and avoids relying on CHECK_NONFATAL in the success path.
🧹 Nitpick comments (1)
src/llmq/signing.h (1)
211-218: Minor redundancy: public GetDb() with friend declaration.The code has both a public
GetDb()method and a friend declaration forCSigSharesManager. The friend declaration is necessary to access the privateProcessRecoveredSig()method (line 214), but havingGetDb()public makes the friend access to it redundant.If
GetDb()should only be accessible toCSigSharesManager, consider moving it to private/protected:+private: + // Used by CSigSharesManager + CRecoveredSigsDb& GetDb() { return db; } + void ProcessRecoveredSig(const std::shared_ptr<const CRecoveredSig>& recoveredSig, PeerManager& peerman) + EXCLUSIVE_LOCKS_REQUIRED(!cs_pending, !cs_listeners); + + // Needed for access to GetDb() and ProcessRecoveredSig() + friend class CSigSharesManager; + public: - // Used by CSigSharesManager - CRecoveredSigsDb& GetDb() { return db; } - void ProcessRecoveredSig(const std::shared_ptr<const CRecoveredSig>& recoveredSig, PeerManager& peerman) - EXCLUSIVE_LOCKS_REQUIRED(!cs_pending, !cs_listeners); - - // Needed for access to GetDb() and ProcessRecoveredSig() - friend class CSigSharesManager; - -public: // public interfaceHowever, if other code legitimately needs direct database access, the current design is acceptable.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (14)
src/chainlock/chainlock.h(2 hunks)src/chainlock/signing.cpp(2 hunks)src/instantsend/signing.cpp(3 hunks)src/llmq/context.cpp(2 hunks)src/llmq/ehf_signals.cpp(2 hunks)src/llmq/signing.cpp(2 hunks)src/llmq/signing.h(4 hunks)src/llmq/signing_shares.cpp(37 hunks)src/llmq/signing_shares.h(4 hunks)src/masternode/active/context.cpp(3 hunks)src/masternode/active/notificationinterface.cpp(2 hunks)src/masternode/active/notificationinterface.h(2 hunks)src/net_processing.cpp(1 hunks)src/rpc/quorums.cpp(5 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- src/masternode/active/notificationinterface.cpp
- src/net_processing.cpp
- src/masternode/active/notificationinterface.h
🧰 Additional context used
📓 Path-based instructions (2)
src/**/*.{cpp,h,cc,cxx,hpp}
📄 CodeRabbit inference engine (CLAUDE.md)
src/**/*.{cpp,h,cc,cxx,hpp}: Dash Core C++ codebase must be written in C++20 and require at least Clang 16 or GCC 11.1
Dash uses unordered_lru_cache for efficient caching with LRU eviction
Files:
src/llmq/signing_shares.hsrc/llmq/ehf_signals.cppsrc/rpc/quorums.cppsrc/llmq/signing_shares.cppsrc/masternode/active/context.cppsrc/llmq/context.cppsrc/chainlock/signing.cppsrc/instantsend/signing.cppsrc/llmq/signing.cppsrc/llmq/signing.hsrc/chainlock/chainlock.h
src/{masternode,evo}/**/*.{cpp,h,cc,cxx,hpp}
📄 CodeRabbit inference engine (CLAUDE.md)
Masternode lists must use immutable data structures (Immer library) for thread safety
Files:
src/masternode/active/context.cpp
🧠 Learnings (1)
📚 Learning: 2025-10-02T18:29:54.756Z
Learnt from: kwvg
PR: dashpay/dash#6840
File: src/net_processing.cpp:2882-2886
Timestamp: 2025-10-02T18:29:54.756Z
Learning: Across net_processing.cpp, once LLMQContext (m_llmq_ctx) is asserted non-null, its subcomponents (e.g., isman, qdkgsman, quorum_block_processor) are treated as initialized and used without extra null checks.
Applied to files:
src/llmq/context.cpp
🧬 Code graph analysis (8)
src/llmq/signing_shares.h (1)
src/llmq/signing.cpp (10)
StartWorkerThread(707-715)StartWorkerThread(707-707)InterruptWorkerThread(729-732)InterruptWorkerThread(729-729)ProcessMessage(393-433)ProcessMessage(393-393)Cleanup(635-648)Cleanup(635-635)WorkThreadMain(734-746)WorkThreadMain(734-734)
src/rpc/quorums.cpp (1)
src/llmq/signing_shares.cpp (2)
SelectMemberForRecovery(856-869)SelectMemberForRecovery(856-856)
src/llmq/signing_shares.cpp (4)
src/llmq/signing.cpp (8)
StartWorkerThread(707-715)StartWorkerThread(707-707)WorkThreadMain(734-746)WorkThreadMain(734-734)ProcessMessage(393-433)ProcessMessage(393-393)Cleanup(635-648)Cleanup(635-635)src/llmq/quorums.cpp (4)
ProcessMessage(701-884)ProcessMessage(701-701)SelectQuorumForSigning(1204-1264)SelectQuorumForSigning(1204-1205)src/llmq/signing_shares.h (1)
MAX_MSGS_SIG_SHARES(377-493)src/masternode/active/notificationinterface.cpp (2)
NotifyRecoveredSig(30-33)NotifyRecoveredSig(30-30)
src/masternode/active/context.cpp (3)
src/llmq/context.cpp (6)
Interrupt(46-49)Interrupt(46-46)Start(51-57)Start(51-51)Stop(59-65)Stop(59-59)src/init.cpp (2)
Interrupt(227-250)Interrupt(227-227)src/instantsend/instantsend.cpp (4)
Start(76-88)Start(76-76)Stop(90-104)Stop(90-90)
src/llmq/context.cpp (3)
src/instantsend/signing.cpp (4)
Start(49-52)Start(49-49)Stop(54-57)Stop(54-54)src/masternode/active/context.cpp (4)
Start(54-59)Start(54-54)Stop(61-66)Stop(61-61)src/chainlock/chainlock.cpp (4)
Start(65-82)Start(65-65)Stop(84-90)Stop(84-84)
src/llmq/signing.cpp (1)
src/llmq/signing.h (1)
CSigningManager(162-243)
src/llmq/signing.h (2)
src/llmq/signing.cpp (5)
CSigningManager(335-340)ProcessRecoveredSig(578-622)ProcessRecoveredSig(578-578)Cleanup(635-648)Cleanup(635-635)src/llmq/signing_shares.cpp (4)
CSigSharesManager(183-195)CSigSharesManager(197-197)Cleanup(1380-1514)Cleanup(1380-1380)
src/chainlock/chainlock.h (1)
src/chainlock/chainlock.cpp (2)
CChainLocksHandler(46-57)CChainLocksHandler(59-63)
🪛 GitHub Actions: Clang Diff Format Check
src/llmq/signing_shares.h
[error] 442-442: Clang format differences found. Run clang-format to fix formatting in this file.
src/masternode/active/context.cpp
[error] 46-46: Clang format differences found. Run clang-format to fix formatting in this file.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Build container / Build container
🔇 Additional comments (26)
src/chainlock/chainlock.h (2)
73-74: Constructor update looks correct.Removal of CSigningManager& aligns with implementation and ownership shift.
70-70: Fix chrono literal in header (compile blocker).0s requires std::chrono_literals; headers shouldn’t rely on using-directives. Initialize explicitly.
- std::atomic<std::chrono::seconds> lastCleanupTime{0s}; + std::atomic<std::chrono::seconds> lastCleanupTime{std::chrono::seconds{0}};⛔ Skipped due to learnings
Learnt from: kwvg PR: dashpay/dash#6815 File: src/chainlock/chainlock.h:68-69 Timestamp: 2025-08-13T16:10:32.972Z Learning: The Dash codebase extensively uses std::chrono_literals throughout, including in header files. Chrono literals like 0s, 1min, etc. are acceptable and preferred over explicit constructors like std::chrono::seconds::zero().Learnt from: kwvg PR: dashpay/dash#6815 File: src/chainlock/chainlock.h:68-69 Timestamp: 2025-08-13T16:10:32.972Z Learning: The Dash codebase extensively uses std::chrono_literals throughout, including in header files. The pattern using namespace std::chrono_literals; is used globally in src/util/time.h, and chrono literals like 0s are commonly used for atomic member initialization in headers (e.g., src/net.h). Chrono literals like 0s, 1min, etc. are preferred over explicit constructors.src/llmq/signing_shares.h (5)
407-413: Objective mismatch: CActiveMasternodeManager still a hard dependency.Member m_mn_activeman and ctor parameter persist, contrary to “drop CActiveMasternodeManager from CSigSharesManager”.
- If the intent is to eliminate this dep, consider:
- Injecting only required data (e.g., local ProTxHash) via an abstracted provider, or
- Querying membership via qman and peerman (verified ProRegTx) without mn_activeman.
Would you like a follow-up patch to remove the dependency fully?Also applies to: 419-423
443-447: AsyncSignIfMember moved here: ACK.Signature matches usage sites (sigman passed in). No issues.
448-449: NotifyRecoveredSig hook: ACK.Provides relay via peerman outside CSigningManager.
1-496: Developer must manually run clang-format to fix reported formatting differences.The file
src/llmq/signing_shares.hexists (496 lines as shown), but clang-format tool is unavailable in this verification environment. Since CI is reporting formatting failures, run clang-format locally using either:contrib/devtools/clang-format.py -p src/llmq/signing_shares.h # or clang-format -i src/llmq/signing_shares.hThen commit the formatting changes to resolve the CI pipeline failure.
432-432: ProcessMessage signature update verified complete.All call sites have been correctly updated. The single call at
src/net_processing.cpp:5380uses the new 3-parameter signature without the sporkman reference, matching both the header declaration and implementation insrc/llmq/signing_shares.{h,cpp}. No legacy 4-parameter calls remain.src/chainlock/signing.cpp (1)
12-12: AsyncSignIfMember call switched to shareman: ACK.Include added and call matches new API.
Also applies to: 144-145
src/llmq/signing.cpp (1)
333-341: CSigningManager dep cleanup: ACK.
- Ctor no longer needs CActiveMasternodeManager.
- Worker thread renamed to “recsigs”.
- Relaying moved out; GetDb exposed as friend for shareman.
Also applies to: 714-715
src/instantsend/signing.cpp (1)
16-17: InstantSend signing paths use shareman.AsyncSignIfMember: ACK.Matches refactor; no functional concerns spotted.
Also applies to: 334-335, 392-393
src/llmq/ehf_signals.cpp (1)
14-18: EHF signals: include updates and shareman.AsyncSignIfMember usage: ACK.Consistent with new API.
Also applies to: 81-82
src/llmq/context.cpp (1)
33-37: I need to gather more information to fully verify the review comment. Let me search for call sites and related method changes:I need to search the codebase directly to verify the lifecycle changes. Let me run more targeted queries:
Verify the Start() call sites in the codebase and check for Interrupt/Stop methods
Based on the script output provided, I can verify the key change mentioned in the review comment. The executed rg command confirmed that the
Startmethod at line 51 insrc/llmq/context.cppnow takesPeerManager&as its only parameter:void LLMQContext::Start(PeerManager& peerman)This matches the review comment's claim that "Start now takes PeerManager only."
However, I cannot fully verify the other claims in the review comment (shareman lifecycle moved to ActiveContext, sigman worker moved) without access to the full codebase context and previous versions of the code. The snippet provided shows the member initializations at lines 33-37 using
std::make_unique, but without seeing the complete class definition, related files (ActiveContext, previous code state), and call sites, I cannot definitively confirm all the lifecycle changes mentioned.src/masternode/active/context.cpp (2)
29-37: LGTM! Proper dependency injection and initialization order.The shareman is correctly instantiated before being passed to dependent components (ehf_sighandler, cl_signer, is_signer), ensuring proper initialization order.
49-66: LGTM! Proper lifecycle management with LIFO ordering.The Start/Stop/Interrupt methods follow correct LIFO ordering:
- Start: DKG threads → shareman registration → shareman worker
- Stop: shareman worker → shareman unregister → DKG threads
This ensures clean shutdown and matches the pattern used in LLMQContext.
Note: There's a clang-format issue on line 46 (empty line) flagged by CI that should be addressed.
src/rpc/quorums.cpp (2)
443-445: LGTM! Proper enforcement of masternode-mode requirement.This check correctly enforces the documented breaking change that quorum sign RPC requires masternode-mode. The error message is clear and the check placement prevents execution of signing operations without the required context.
750-750: LGTM! Correct usage of static method.The call correctly uses the static method
CSigSharesManager::SelectMemberForRecovery, which is appropriate as this function doesn't require instance state.src/llmq/signing.h (2)
23-25: LGTM! Necessary includes for standard library types.The includes are justified:
<memory>forstd::unique_ptr<CDBWrapper>(line 119)<thread>forstd::thread workThread(line 234)
183-183: LGTM! Constructor signature correctly removes active masternode dependency.The removal of the
CActiveMasternodeManagerparameter aligns with the PR's objective to decouple CSigningManager from active masternode concerns. This responsibility is now handled by CSigSharesManager.src/llmq/signing_shares.cpp (8)
183-197: LGTM! Clean dependency injection and RAII design.The constructor properly injects all required dependencies as references, and initializes the worker interrupt. The default destructor is appropriate since cleanup is handled by explicit Stop() methods.
199-207: LGTM! Simplified thread start with member-based access.The parameterless
StartWorkerThread()correctly capturesthisto access member variables. Since all dependencies are stored as members initialized at construction, this is thread-safe.
236-313: LGTM! Consistent member-based access pattern.The ProcessMessage method correctly uses direct member access (
m_mn_activeman,m_sporkman) and consistently extracts node ID from theCNodereference. The early return for non-masternode mode (line 239) is appropriate.
871-949: LGTM! AsyncSignIfMember correctly relocated with proper dependencies.The method has been successfully moved from CSigningManager to CSigSharesManager, now accepting
CSigningManager&as a parameter. The implementation:
- Correctly uses member access for active masternode and chainstate
- Properly accesses the signing manager's database via friend access
- Maintains the original voting and conflict checking logic
- Ends with
AsyncSign()to queue the signing operationThe method is thread-safe as it uses explicit locking (
cs_pendingSignsviaAsyncSign) and the database has its own internal locking.
951-954: LGTM! Clean delegation of recovery signature relay.The
NotifyRecoveredSig()method properly delegates to the peer manager for relaying. TheAssert()ensures the signature pointer is valid before dereferencing, which is appropriate as this is called from internal code paths where the signature should always be valid.
775-854: LGTM! Proper signature recovery and processing flow.The
TryRecoverSigmethod correctly:
- Handles single-member quorums (lines 792-809) and multi-member quorums (lines 811-851)
- Validates recovered signatures periodically (line 842)
- Delegates to
sigman.ProcessRecoveredSig()with the peer manager referenceThe sporadic self-verification (line 842-850) is a good practice to catch bugs without impacting performance.
1632-1700: LGTM! Consistent signature creation with member-based access.The
CreateSigSharemethod correctly:
- Uses direct member access for active masternode (
m_mn_activeman)- Handles both single-member (operator key) and multi-member (skShare) quorums
- Maintains the existing TODO about single-member signing key (line 1651)
The conversion from pointer-based to member-based access is consistent and correct.
1148-1600: LGTM! Comprehensive and consistent refactor to member-based access.The refactor systematically replaces parameter passing with member access throughout:
m_connmanfor connection management and messagingm_peermanfor peer management and banningm_mn_activemanfor masternode identitym_sporkmanfor spork checksAll changes maintain thread safety as these members are initialized at construction and accessed appropriately. The messaging flow (
PushMessage), banning logic (Misbehaving), and node iteration (ForEachNode) all work correctly with the member-based pattern.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
overall LGTM, not super confident
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
utACK af9a15f
Additional Information
Depends on refactor: drop
fMasternodeModeglobal, create new context for masternode mode-only logic (ActiveContext), move spun-off signers and EHF signals handler #6828Depends on chore: consolidate oft-repeated type definitions to
{evo,llmq}/types.h#6839This pull request does not address
CQuorumManagerorCDKGSessionManageras both complicate signer separation as they accommodate watch-only mode (source, source) and allow for LLMQ data recovery enablement (source), which makes them better suited for a separate PR.In contrast,
CSigSharesManagercan be more-or-less wholesale moved toActiveContext, the objective of this PR.As part of isolating masternode-mode logic
CSigningManager::AsyncSignIfMember(), which acceptsCSigSharesManageras an argument, was moved toCSigSharesManageracceptingCSigningManageras argument. This required exposing the recovered signatures DB toCSigningManager, which has been done withGetDb().ActiveContext, thequorum signRPC will only work if masternode-mode is enabledTo allow dropping
CActiveMasternodeManagerfromCSigningManager, we needed to drop aRelayRecoveredSig()call that is only done in masternode-mode (source). To do that, we rely on theNotifyRecoveredSig()signal that is invoked at the tail ofCSigningManager::ProcessRecoveredSig()(source) by havingActiveNotificationInterfaceslot in, acting in response to the notification rather than before (i.e. existing behavior).Breaking Changes
The
quorum signRPC will only work if masternode-mode is enabled.Checklist